package edu.hit.irlab.coref.resolve.algorithm;

import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import nlpeap.config.ConfigProperties;

import edu.hit.irlab.coref.CRConfigProperties;
import edu.hit.irlab.coref.PairInstance;
import edu.hit.irlab.coref.mentionfinder.Mention;
import edu.hit.irlab.coref.resolve.Entity;
import edu.hit.irlab.coref.resolve.Resolver;

/**
 * The abstract class of the algorithm of resolving <i>Mentions</i>
 * @author chuter
 *
 */
public abstract class ResolveAlgorithm {
	//the log for resolving
	protected static final CRConfigProperties _crprop = CRConfigProperties.getInstance();
	public static Log _log = LogFactory.getLog(_crprop.getResolveLog());
	protected final static boolean _debug = _crprop.isDebug();
	
	protected final Resolver[] _resolvers;
	//the step size of looking for the Antecedent of an Anaphor,
	//and take Mention as unit
	protected int CHUNK_SIZE = 10;
	protected static double _threshold = 
		ConfigProperties.getInstance().getClassifyThreshold();
	
	public ResolveAlgorithm(Resolver[] resolvers)
	{ _resolvers = resolvers; }
	
	/** get the max score among all the scores of the resolvers */
	protected double maxScore(PairInstance ins)
	{
		double corf_value = -1000.0;
		Resolver best_Resolver = null;
        for (Resolver resolver : this._resolvers) {
        	if (!resolver.canResolve(ins))
        		continue;
        	double value = resolver.score(ins);
        	if (value > corf_value) {
        		corf_value = value;
        		best_Resolver = resolver;
        	}
        }
        
        if (_debug) {
        	//the best_Resolver can't be empty
        	assert (best_Resolver != null);
        	_log.info(String.format("Instance:%s\n%s\t[%s]\t[%f]\n", ins.toString(),
        			ins.allFeatures(), best_Resolver.toString(), corf_value));
        }
        
        return corf_value;
	}
	
	/** If two mentions are resolved as coreference, this function
	 *  is to record whether the resolve result is right or wrong,
	 *  to make the analysis of the result easier. <br> 
	 *  The information write to <i>logfile</i> using <i>log4j</i> */
	protected void debug(Mention ans, Mention ana) {
		if (!_debug)
			return;
		
		if (ans.getSetId()==-1 || ana.getSetId()==-1)
			return;
		
		PairInstance ins = new PairInstance(ans, ana);
		//the coreference information has been annotated
		if (ans.getSetId() == ana.getSetId())
			//the resolve result is right
			_log.info(String.format("Right Instance:%s\n%s\n", 
					ins.toString(), ins.allFeatures()));
		else
			//the resolve result is wrong
			_log.info(String.format("Wrong Instance:%s\n%s\n", 
					ins.toString(), ins.allFeatures()));
		
	}
	
	/** set the <code>CHUNK_SIZE</code> */
	public void setChunkSize(int chunk_size) { this.CHUNK_SIZE = chunk_size; }
	/** set the threshold, the corference probability for
	 *  the instance must beyond this value then the instance
	 *  can be set to be corferenced */
	public void setThrehold(double threshold) { this._threshold = threshold; }
	
	/** cluster all the <i>Mentions</i> into <i>Entity</i> */
	public abstract ArrayList<Entity> resolve(Mention[] mentions);
	/** resolve just one <i>Mention</i>, return the index in
	 *  the mentions array of the <i>Antecedent</i> for the 
	 *  <i>Anaphor</i> */
	public abstract int resolveSingle(Mention[] mentions, int ana);
}
